#include "head.h"
#include "lua_timerfd.h"

/*
	usage:  create()
	paras:  \
	return: [tfd]、[nil, errno]
*/
static int l_timerfd_create(lua_State *L) {
	int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
	if (fd == -1) {
		lua_pushnil(L);
		lua_pushstring(L, strerror(errno));
		return 2;
	}
	lua_pushinteger(L, fd);
	return 1;
}

/*
	usage:  close(tfd)
	paras:  tfd
	return: [errno]
*/
static int l_timerfd_close(lua_State *L) {
	int fd = luaL_checkinteger(L, 1);
	if (close(fd) == -1) {
		lua_pushstring(L, strerror(errno));
		return 1;
	}
	return 0;
}

/*
	usage:  settime(tfd, time)
	paras:  tfd, time(ms)
	return: 
*/
static int l_timerfd_settime(lua_State *L) {
	int fd = luaL_checkinteger(L, 1);
	lua_Integer delay = luaL_checkinteger(L, 2);

	struct itimerspec timer;
	time_t sec = delay / 1000; // delay 以ms毫秒为单位
	long nsec = 1000000 * (delay % 1000);

	timer.it_interval.tv_sec = sec; 
	timer.it_interval.tv_nsec = nsec; 

	timer.it_value.tv_sec = sec;
	timer.it_value.tv_nsec = nsec;

	if (timerfd_settime(fd, 0, &timer, NULL) == -1) {
		lua_pushstring(L, strerror(errno));
		return 1;
	}
	return 0;
}

/*
	usage:  gettime(tfd)
	paras:  tfd
	return: [current]、[nil, errno]
*/
static int l_timerfd_gettime(lua_State *L) {
	struct itimerspec current;
	int fd = luaL_checkinteger(L, 1);

	if (timerfd_gettime(fd, &current) == -1) {
		lua_pushnil(L);
		lua_pushstring(L, strerror(errno));
		return 2;
	}

	lua_newtable(L); // [table]

	lua_pushstring(L, "it_value"); // [table, "it_value"]
	lua_newtable(L); // [table, "it_value", table]
	lua_pushstring(L, "tv_sec"); // [table, "it_value", table, "tv_sec"]
	lua_pushinteger(L, current.it_value.tv_sec); // [table, "it_value", table, "tv_sec", int]
	lua_settable(L, -3); // [table, "it_value", table]
	lua_pushstring(L, "tv_nsec"); // [table, "it_value", table, "tv_nsec"]
	lua_pushinteger(L, current.it_value.tv_nsec); // [table, "it_value", table, "tv_nsec", int]
	lua_settable(L, -3); // [table, "it_value", table]
	lua_settable(L, -3); // [table]

	lua_pushstring(L, "it_interval"); // [table, "it_interval"]
	lua_newtable(L); // [table, "it_interval", table]
	lua_pushstring(L, "tv_sec"); // [table, "it_interval", table, "tv_sec"]
	lua_pushinteger(L, current.it_interval.tv_sec); // [table, "it_interval", table, "tv_sec", int]
	lua_settable(L, -3); // [table, "it_interval", table]
	lua_pushstring(L, "tv_nsec"); // [table, "it_interval", table, "tv_nsec"]
	lua_pushinteger(L, current.it_interval.tv_nsec); // [table, "it_interval", table, "tv_nsec", int]
	lua_settable(L, -3); // [table, "it_interval", table]
	lua_settable(L, -3); // [table]

	return 1;
}

/*
	usage:  read(tfd)
	paras:  tfd
	return: [true]、[false, errno]
*/
static int l_timerfd_read(lua_State *L) {
	static uint64_t time; 
	int fd = luaL_checkinteger(L, 1);
	if (read(fd, &time, sizeof(uint64_t)) != sizeof(uint64_t)) {
		lua_pushboolean(L, false); 
		lua_pushstring(L, strerror(errno));
		return 2;
	}
	lua_pushboolean(L, true);
	return 1;
}

int lua_lib_timerfd(lua_State *L) {
	static const struct luaL_Reg l[] = {
		{ "create", l_timerfd_create },
		{ "close", l_timerfd_close }, 
		{ "read", l_timerfd_read },
		{ "settime", l_timerfd_settime },
		{ "gettime", l_timerfd_gettime }, 
		{ NULL, NULL }
	};

	luaL_newlib(L, l);
	return 1;
}